#ifndef MODULES_HEADER_FROM_CORE_INCLUDED
#define MODULES_HEADER_FROM_CORE_INCLUDED
////////////////////////////////////////////////////////////////////////////////
//	Copyright (c) 2004 by Michael 'Astar' Sotnikov
//	stari4ek at gmail dot com
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <vector>
#include <map>

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>

#include <loki/Singleton.h>

#include "cSmartAssert.hpp"


class Module_c{
	friend class ModuleRegister_c;
	
protected:
							Module_c();
	virtual					~Module_c();

	template<typename RealModule_t>
	static Module_c&		ModuleInstance(){
		BOOST_STATIC_ASSERT( ( boost::is_base_of<Module_c, RealModule_t>::value ) );

		static RealModule_t me;
		return me;
	}

	virtual	bool			ModuleInit();
	virtual	bool			ModuleDone();

	virtual const char*		ModuleName() const = 0;
	// return null-terminated list
	virtual const char* *	ModuleDependsOn() const = 0;

	bool					IsActive() const;

private:
	bool					m_active;
};

/* There are some stages and states in register:
	- all modules must be registered (CORE_MODULE_REGISTER works pretty well, 
			it uses static stage of unit's exec)
	- main exec unit defines which modules have to be active. When and where.
*/
class ModuleRegister_c{
	template <class> friend struct Loki::CreateUsingNew;

	typedef Module_c& (*CreatorFn_t)();
	typedef std::map< std::string, CreatorFn_t >	Creators_t;
	
public:
	template<typename Module_t>
	void				Register(){
		BOOST_STATIC_ASSERT( ( boost::is_base_of<Module_c, Module_t>::value ) );

		SMART_VERIFY( 	m_creators.insert( 
							std::make_pair( Module_t::m_name, &Module_c::ModuleInstance<Module_t> ) 
						).second
		)
			( Module_t::m_name )
			.error( "Can't register module with same name." );
	}

	void				Activate( const std::string& name );
	void				Deactivate( const std::string& name );

	bool				IsRegistered( const std::string& name ) const;
	bool				IsActive( const std::string& name ) const;

protected:
						ModuleRegister_c();
private:
	// forbidden
						ModuleRegister_c( const ModuleRegister_c& );
	ModuleRegister_c&	operator=( const ModuleRegister_c& );
	ModuleRegister_c*	operator*( const ModuleRegister_c& );

private:
	Creators_t			m_creators;
};

typedef Loki::SingletonHolder<	ModuleRegister_c,
								Loki::CreateUsingNew,
								Loki::PhoenixSingleton> g_ModuleRegister;

namespace core{
	template<typename Module_t>
	struct ModuleRegisterHelper_T{
		ModuleRegisterHelper_T(){
			g_ModuleRegister::Instance().Register<Module_t>();
		}
	};
};


#define CORE_MODULE_DECLARE(module)							\
	public:													\
		static const char*		m_name;						\
		static const char*		m_prereqs[];				\
	public:													\
		virtual const char*		ModuleName() const{			\
			return m_name;									\
		}													\
		virtual const char* *	ModuleDependsOn() const{	\
			return m_prereqs;								\
		}


// we use static object, which does all register's things in constructor
// WARN: some super-clever compilers (hi bill!) can remove it, cause it's global
// static object, and there is no any references from real code. 
#define CORE_MODULE_REGISTER(module) \
	static core::ModuleRegisterHelper_T<module> module ## _registrator;



#endif /*MODULES_HEADER_FROM_CORE_INCLUDED*/
